#include <iostream>
#include <string>
#include <cerrno>

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define NUM 1024
const uint16_t port = 8080;

int main()
{
    //创建套接字，打开网络文件
    //可以man socket查看
    // AF_INET -- IPv4 Internet protocols
    // SOCK_DGRAM UDP协议
    // SOCK_DGRAM --Supports  datagrams  (connectionless,  unreliable messages of a fixed maximum  length
    // int socket(int domain, int type, int protocol)
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        std::cerr << "socket create error: " << errno << std::endl;
        return 1;
    }

    //给服务器绑定端口和ip
    // man 3 bind
    // man inet_addr
    //sockaddr 相当于重载 可以sockaddr_in /sockaddr_un 
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    //端口号 htons主机序列转网络序列
    local.sin_port = htons(port);

    // ip
    // 1.要人识别的点分十进制字符串风格IP转为4字节整数IP
    // 2.考虑大小端
    // in_addr_t inet_addr(const char *cp) 就能完成1.2.
    //云服务不允许用户bind公网IP
    //如果bing的确定的IP（主机）,只有发送到该IP上的数据才会交给网络进程，我们需要的是所有发送到该主机的数据
    // INADDR_ANY:0 就可以接收所有发给该主机数据
    local.sin_addr.s_addr = INADDR_ANY;

    // int bind(int socket, const struct sockaddr *address,
    //  socklen_t address_len);
    if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        std::cerr << "bind error: " << errno << std::endl;
        return 2;
    }

    //提供服务
    bool quit = false;
    char buffer[NUM];
    while (!quit)
    {
        //开好空间和大小来放通信客户socket信息
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        //读
        /*  ssize_t recvfrom(int socket, 
       //通信内容 void *restrict buffer, size_t length, int flags,
              //和你服务器通信客户的socket信息
               struct sockaddr *restrict address, socklen_t *restrict address_len);*/
        recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);

        std::cout << "client# " << buffer << std::endl;
        //自己定义的
        std::string echo_hello = "hello";
        //给客户返回去
        /* ssize_t sendto(int socket, const void *message, size_t length,
              int flags, const struct sockaddr *dest_addr,
              socklen_t dest_len); */
        sendto(sock, echo_hello.c_str(), echo_hello.size(), 0, (struct sockaddr *)&peer, len);
    }
    return 0;
}